package com.mall.mall.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.mall.common.utils.R;
import com.mall.mall.seckill.feign.CouponFeignService;
import com.mall.mall.seckill.feign.ProductFeignService;
import com.mall.mall.seckill.service.SeckillService;
import com.mall.mall.seckill.to.SeckillSkuRedisTO;
import com.mall.mall.seckill.vo.SeckillSessionVO;
import com.mall.mall.seckill.vo.SeckillSkuRelationEntityVO;
import com.mall.mall.seckill.vo.SkuInfoVO;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.swing.plaf.synth.SynthOptionPaneUI;
import javax.xml.crypto.Data;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class SeckillServiceImpl implements SeckillService {

    @Autowired
    CouponFeignService couponFeignService;

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RedissonClient redissonClient;

    private final String SESSIONS_CACHE_PREFIX = "seckill:sessions:";
    private final String SKUKILL_CACHE_PREFIX = "seckill:skus";
    private final String Sku_STOCK_SEMAPHORE = "seckill:stock:";

    @Override
    public void uploadSeckillSkuLatest3Days() {
        R response = couponFeignService.getLasted3DaysSession();
        if (0 == response.getCode()){
            // 上架商品
            List<SeckillSessionVO> seckillSessionVO = response.getData(new TypeReference<List<SeckillSessionVO>>() {});
            saveSessionInfos(seckillSessionVO);
            saveSessionSkuInfos(seckillSessionVO);
        }

    }

    @Override
    public List<SeckillSkuRedisTO> getCurrentSeckillSkus() {
        long time = new Date().getTime();

        Set<String> keys = redisTemplate.keys(SESSIONS_CACHE_PREFIX + "*");
        for (String key : keys){
            String replace = key.replace(SESSIONS_CACHE_PREFIX, "");
            String[] s = replace.split("_");
            long startTime = Long.parseLong(s[0]);
            long endTime = Long.parseLong(s[1]);
            Date date = new Date(startTime);
            Date date1 = new Date(time);
            if (time >= startTime && time <= endTime){
                List<String> range = redisTemplate.opsForList().range(key, -100, 100);
                BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);
                List<String> list = boundHashOperations.multiGet(range);
                if (!CollectionUtils.isEmpty(list)){
                    List<SeckillSkuRedisTO> collect = list.stream().map(item -> {
                        SeckillSkuRedisTO seckillSkuRedisTO = JSON.parseObject(item, SeckillSkuRedisTO.class);
//                        seckillSkuRedisTO.setRandomCode(null);
                        return seckillSkuRedisTO;
                    }).collect(Collectors.toList());
                    return collect;
                }
                break;
            }

        }

        return null;
    }

    @Override
    public SeckillSkuRedisTO getSkuSeckillInfo(Long skuId) {

        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);
        Set<String> keys = boundHashOperations.keys();
        if (!CollectionUtils.isEmpty(keys)){
            String regx = "\\d_" + skuId;
            for (String key : keys) {
                if (Pattern.matches(regx, key)){
                    String o = (String) boundHashOperations.get(key);
                    SeckillSkuRedisTO seckillSkuRedisTO = JSON.parseObject(o, SeckillSkuRedisTO.class);

                    Long startTime = seckillSkuRedisTO.getStartTime();
                    Long endTime = seckillSkuRedisTO.getEndTime();
                    long currenTime = new Date().getTime();

                    if (currenTime < startTime || currenTime > endTime){
                        seckillSkuRedisTO.setRandomCode(null);
                    }

                    return seckillSkuRedisTO;
                }

            }
        }

        return null;
    }

    private void saveSessionInfos(List<SeckillSessionVO> sessions){
        sessions.stream().forEach(session -> {
            long startTime = session.getStartTime().getTime();
            long endTime = session.getEndTime().getTime();
            String key = SESSIONS_CACHE_PREFIX + startTime + "_" + endTime;
            Boolean aBoolean = redisTemplate.hasKey(key);
            if (!aBoolean){
                List<String> collect = session.getRelationSkus().stream().map(item -> item.getPromotionSessionId()+"_"+item.getSkuId().toString()).collect(Collectors.toList());
                redisTemplate.opsForList().leftPushAll(key, collect);
            }
        });
    }

    private void saveSessionSkuInfos(List<SeckillSessionVO> sessions){
        sessions.stream().forEach(session -> {
            BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);
            session.getRelationSkus().stream().forEach(seckillSkuVo -> {
                String redisKey = seckillSkuVo.getPromotionSessionId().toString() + "_" + seckillSkuVo.getSkuId().toString();
                if (!boundHashOperations.hasKey(redisKey)){
                    // 缓存商品
                    SeckillSkuRedisTO seckillSkuRedisTO = new SeckillSkuRedisTO();
                    // 1、sku 基本信息
                    R response = productFeignService.getSkuInfo(seckillSkuVo.getSkuId());
                    if(0 == response.getCode()){
                        SkuInfoVO skuInfo = response.getData("skuInfo", new TypeReference<SkuInfoVO>() {});
                        seckillSkuRedisTO.setSkuInfo(skuInfo);
                    }

                    // 2、sku 秒杀信息
                    BeanUtils.copyProperties(seckillSkuVo, seckillSkuRedisTO);

                    // 3、设置上当前商品的秒杀时间信息
                    seckillSkuRedisTO.setStartTime(session.getStartTime().getTime());
                    seckillSkuRedisTO.setEndTime(session.getEndTime().getTime());

                    // 4、随机码
                    String token = UUID.randomUUID().toString().replace("_", "");
                    seckillSkuRedisTO.setRandomCode(token);

                    RSemaphore semaphore = redissonClient.getSemaphore(Sku_STOCK_SEMAPHORE + token);
                    semaphore.trySetPermits(seckillSkuVo.getSeckillCount().intValue());

                    String jsonString = JSON.toJSONString(seckillSkuRedisTO);
                    boundHashOperations.put(seckillSkuVo.getPromotionSessionId().toString()+"_"+seckillSkuVo.getSkuId().toString(), jsonString);
                }
            });
        });
    }
}
